package com.gitee.techstack.util;

import com.gitee.techstack.config.CustomizeTableRuleConfig;
import com.gitee.techstack.constant.ShardingConstant;
import org.apache.commons.lang3.StringUtils;
import org.apache.shardingsphere.core.yaml.config.sharding.YamlKeyGeneratorConfiguration;
import org.apache.shardingsphere.core.yaml.config.sharding.YamlShardingStrategyConfiguration;
import org.apache.shardingsphere.core.yaml.config.sharding.YamlTableRuleConfiguration;
import org.apache.shardingsphere.core.yaml.config.sharding.strategy.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * ┏┓　　　┏┓
 * ┏┛┻━━━┛┻┓
 * ┃　　　　　　　┃
 * ┃　　　━　　　┃
 * ┃　┳┛　┗┳　┃
 * ┃　　　　　　　┃
 * ┃　　　┻　　　┃
 * ┃　　　　　　　┃
 * ┗━┓　　　┏━┛
 * 　　┃　　　┃神兽保佑
 * 　　┃　　　┃代码无BUG！
 * 　　┃　　　┗━━━┓
 * 　　┃　　　　　　　┣┓
 * 　　┃　　　　　　　┏┛
 * 　　┗┓┓┏━┳┓┏┛
 * 　　　┃┫┫　┃┫┫
 * 　　　┗┻┛　┗┻┛
 *
 * @author Yeoman
 * @description
 * @create 2019/12/30 下午5:28
 **/
public class TableRuleUtil {

    private static Logger log = LoggerFactory.getLogger(TableRuleUtil.class);

    private static final String ALGORITHM_PAGE = "com.gitee.techstack.algorithm.";

    public static Map<String, YamlTableRuleConfiguration> parseTableRule(final CustomizeTableRuleConfig customizeTableRuleConfig,
                                                                         List<String> allTablesRule, Map<String, YamlTableRuleConfiguration> tables) {

        allTablesRule.stream().forEach(tableRule -> {
            // ga_subject_table&tenant_id&&param_sharding&&
            log.debug("deal table rule:{}", tableRule);
            String[] tableDetail = tableRule.split("&", -1);
            String shardColumns = tableDetail[2];
            // 规则处理 分片键,如果表分片键为空,取默认规则分片键
            if (StringUtils.isEmpty(shardColumns)) {
                shardColumns = customizeTableRuleConfig.getDefaultKey();
            }
            YamlTableRuleConfiguration yamlTableRuleConfiguration = new YamlTableRuleConfiguration();
            // 逻辑表
            yamlTableRuleConfiguration.setLogicTable(tableDetail[0]);
            // 分库策略
            yamlTableRuleConfiguration.setDatabaseStrategy(getStrategy(tableDetail[3], shardColumns));
            // 分表策略
            yamlTableRuleConfiguration.setTableStrategy(getStrategy(tableDetail[4], shardColumns));
            // 主键策略
            yamlTableRuleConfiguration.setKeyGenerator(getKeyGenerator(tableDetail[5]));
            tables.put(tableDetail[0], yamlTableRuleConfiguration);
        });

        return tables;
    }

    /**
     * keyGenerator strategy
     *
     * @param keyGenerator
     * @return
     */
    private static YamlKeyGeneratorConfiguration getKeyGenerator(String keyGenerator) {
        if (StringUtils.isEmpty(keyGenerator)) {
            return null;
        } else {
            // id@SNOWFLAKE
            String[] keyRules = keyGenerator.split("@", -1);
            YamlKeyGeneratorConfiguration keyGeneratorConfig = new YamlKeyGeneratorConfiguration();
            keyGeneratorConfig.setColumn(keyRules[0]);
            keyGeneratorConfig.setType(keyRules[1]);
            if ("SNOWFLAKE".equalsIgnoreCase(keyRules[1])) {
                Properties properties = new Properties();
                properties.put("worker.id", 123);
                keyGeneratorConfig.setProps(properties);
            }
            return keyGeneratorConfig;
        }
    }


    /**
     * @param strategyFlag
     * @return
     */
    private static YamlShardingStrategyConfiguration getStrategy(String strategyFlag, String shardColumns) {
        String[] strategyFlags = strategyFlag.split(",", -1);
        YamlShardingStrategyConfiguration shardingStrategyConfig = new YamlShardingStrategyConfiguration();
        try {
            if (strategyFlags[0].equalsIgnoreCase(ShardingConstant.SUFFIX_STANDARD)) {
                // 标准算法
                YamlStandardShardingStrategyConfiguration standardShardConfig = new YamlStandardShardingStrategyConfiguration();
                String preciseAlgorithmClassName = ALGORITHM_PAGE + strategyFlags[1];
                String rangeAlgorithmClassName = ALGORITHM_PAGE + strategyFlags[2];
                standardShardConfig.setShardingColumn(shardColumns);
                standardShardConfig.setPreciseAlgorithmClassName(preciseAlgorithmClassName);
                standardShardConfig.setRangeAlgorithmClassName(rangeAlgorithmClassName);
            } else if (strategyFlags[0].equalsIgnoreCase(ShardingConstant.SUFFIX_COMPLEX)) {
                // 复合算法
                YamlComplexShardingStrategyConfiguration complexShardStrategyConfig = new YamlComplexShardingStrategyConfiguration();
                String algorithmClassName = ALGORITHM_PAGE + strategyFlags[1];
                complexShardStrategyConfig.setAlgorithmClassName(algorithmClassName);
                complexShardStrategyConfig.setShardingColumns(shardColumns);
                shardingStrategyConfig.setComplex(complexShardStrategyConfig);
            } else if (strategyFlag.endsWith(ShardingConstant.SUFFIX_INLINE)) {
                // inline 算法策略
                YamlInlineShardingStrategyConfiguration inlineShardStrategyConfig = new YamlInlineShardingStrategyConfiguration();
                inlineShardStrategyConfig.setShardingColumn(shardColumns);
                inlineShardStrategyConfig.setAlgorithmExpression(strategyFlags[1]);
                shardingStrategyConfig.setInline(inlineShardStrategyConfig);
            } else if (strategyFlag.endsWith(ShardingConstant.SUFFIX_HINT)) {
                // 指定路由算法策略
                YamlHintShardingStrategyConfiguration hintShardStrategyConfiguration = new YamlHintShardingStrategyConfiguration();
                hintShardStrategyConfiguration.setAlgorithmClassName(strategyFlags[1]);
                shardingStrategyConfig.setHint(hintShardStrategyConfiguration);
            } else {
                // none
            }
            return shardingStrategyConfig;
        } catch (Exception e) {
            throw new UnsupportedOperationException("table rule must config right strategy tableDetail[3]");
        }
    }
}
